package com.yz.fanrenmianshi.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessage;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessageRole;
import com.yz.fanrenmianshi.common.ErrorCode;
import com.yz.fanrenmianshi.constant.CommonConstant;
import com.yz.fanrenmianshi.exception.BusinessException;
import com.yz.fanrenmianshi.exception.ThrowUtils;
import com.yz.fanrenmianshi.manager.AiManager;
import com.yz.fanrenmianshi.mapper.MockInterviewMapper;
import com.yz.fanrenmianshi.model.dto.mockinterview.MockInterviewAddRequest;
import com.yz.fanrenmianshi.model.dto.mockinterview.MockInterviewChatMessage;
import com.yz.fanrenmianshi.model.dto.mockinterview.MockInterviewEventRequest;
import com.yz.fanrenmianshi.model.dto.mockinterview.MockInterviewQueryRequest;
import com.yz.fanrenmianshi.model.entity.MockInterview;
import com.yz.fanrenmianshi.model.entity.User;
import com.yz.fanrenmianshi.model.enums.MockInterviewEventEnum;
import com.yz.fanrenmianshi.model.enums.MockInterviewStatusEnum;
import com.yz.fanrenmianshi.service.MockInterviewService;
import com.yz.fanrenmianshi.utils.SqlUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;


import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author K4s1ana
 * @description 针对表【mock_interview(模拟面试)】的数据库操作Service实现
 * @createDate 2025-02-26 17:16:07More actions
 */
@Slf4j
@Service
public class MockInterviewServiceImpl extends ServiceImpl<MockInterviewMapper, MockInterview>
        implements MockInterviewService {

    @Resource
    private AiManager aiManager;

    /**
     * 创建模拟面试
     *
     * @param mockInterviewAddRequest
     * @param loginUser
     * @return
     */
    @Override
    public Long createMockInterview(MockInterviewAddRequest mockInterviewAddRequest, User loginUser) {
        // 1. 参数校验
        if (mockInterviewAddRequest == null || loginUser == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        String workExperience = mockInterviewAddRequest.getWorkExperience();
        String jobPosition = mockInterviewAddRequest.getJobPosition();
        String difficulty = mockInterviewAddRequest.getDifficulty();
        ThrowUtils.throwIf(StrUtil.hasBlank(workExperience, jobPosition, difficulty), ErrorCode.PARAMS_ERROR, "参数错误");
        // 2. 封装插入到数据库中的对象
        MockInterview mockInterview = new MockInterview();
        mockInterview.setWorkExperience(workExperience);
        mockInterview.setJobPosition(jobPosition);
        mockInterview.setDifficulty(difficulty);
        mockInterview.setUserId(loginUser.getId());
        mockInterview.setStatus(MockInterviewStatusEnum.TO_START.getValue());
        // 3. 插入到数据库
        boolean result = this.save(mockInterview);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "创建失败");
        // 4. 返回 id
        return mockInterview.getId();
    }

    /**
     * 获取查询条件
     *
     * @param mockInterviewQueryRequest
     * @return
     */
    @Override
    public QueryWrapper<MockInterview> getQueryWrapper(MockInterviewQueryRequest mockInterviewQueryRequest) {
        QueryWrapper<MockInterview> queryWrapper = new QueryWrapper<>();
        if (mockInterviewQueryRequest == null) {
            return queryWrapper;
        }
        // 从对象中取值
        Long id = mockInterviewQueryRequest.getId();
        String workExperience = mockInterviewQueryRequest.getWorkExperience();
        String jobPosition = mockInterviewQueryRequest.getJobPosition();
        String difficulty = mockInterviewQueryRequest.getDifficulty();
        Integer status = mockInterviewQueryRequest.getStatus();
        Long userId = mockInterviewQueryRequest.getUserId();
        String sortField = mockInterviewQueryRequest.getSortField();
        String sortOrder = mockInterviewQueryRequest.getSortOrder();
        // 补充需要的查询条件
        queryWrapper.eq(ObjectUtils.isNotEmpty(id), "id", id);
        queryWrapper.like(StringUtils.isNotBlank(workExperience), "workExperience", workExperience);
        queryWrapper.like(StringUtils.isNotBlank(jobPosition), "jobPosition", jobPosition);
        queryWrapper.like(StringUtils.isNotBlank(difficulty), "difficulty", difficulty);
        queryWrapper.eq(ObjectUtils.isNotEmpty(status), "status", status);
        queryWrapper.eq(ObjectUtils.isNotEmpty(userId), "userId", userId);
        // 排序规则
        queryWrapper.orderBy(SqlUtils.validSortField(sortField),
                sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        return queryWrapper;
    }

    /**
     * 处理模拟面试事件
     *
     * @param mockInterviewEventRequest
     * @param loginUser
     * @return
     */
    @Override
    public String handleMockInterviewEvent(MockInterviewEventRequest mockInterviewEventRequest, User loginUser) {
        // 区分事件
        Long id = mockInterviewEventRequest.getId();
        if (id == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数错误");
        }
        MockInterview mockInterview = this.getById(id);
        ThrowUtils.throwIf(mockInterview == null, ErrorCode.PARAMS_ERROR, "模拟面试未创建");
        // 如果不是本人创建的模拟面试，报错
        if (!mockInterview.getUserId().equals(loginUser.getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        String event = mockInterviewEventRequest.getEvent();
        MockInterviewEventEnum eventEnum = MockInterviewEventEnum.getEnumByValue(event);
        switch (eventEnum) {
            // -- 处理开始事件
            // 用户进入模拟面试，发送“开始”事件，修改模拟面试的状态为“已开始”，AI 要给出对应的回复
            case START:
                return handleChatStartEvent(mockInterview);
            // -- 处理对话事件
            // 用户可以和 AI 面试官发送消息，发送“消息”事件，携带上要发送的消息内容，AI 要给出对应的回复
            case CHAT:
                return handleChatMessageEvent(mockInterviewEventRequest, mockInterview);
            case END:
                // -- 处理结束事件
                // 退出模拟面试，发送“退出”事件，AI 给出面试的复盘总结，修改状态为“已结束”
                return handleChatEndEvent(mockInterview);
            default:
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数错误");
        }
    }

    /**
     * 处理 AI 对话结束事件
     *
     * @param mockInterview
     * @return
     */
    private String handleChatEndEvent(MockInterview mockInterview) {
        // 检查面试状态
        if (!Objects.equals(MockInterviewStatusEnum.IN_PROGRESS.getValue(), mockInterview.getStatus())) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "面试未在进行中，无法结束");
        }
        
        // 构造消息列表，注意需要先获取之前的消息记录
        String historyMessage = mockInterview.getMessages();
        List<MockInterviewChatMessage> historyMessageList = new ArrayList<>();
        
        // 安全地解析历史消息
        if (StrUtil.isNotBlank(historyMessage)) {
            try {
                historyMessageList = JSONUtil.parseArray(historyMessage).toList(MockInterviewChatMessage.class);
            } catch (Exception e) {
                log.warn("解析历史消息失败，面试ID: {}, 错误: {}", mockInterview.getId(), e.getMessage());
                historyMessageList = new ArrayList<>();
            }
        }
        
        final List<ChatMessage> chatMessages = transformToChatMessage(historyMessageList);
        // 构造用户结束消息
        String endUserPrompt = "结束";
        final ChatMessage endUserMessage = ChatMessage.builder().role(ChatMessageRole.USER).content(endUserPrompt).build();
        chatMessages.add(endUserMessage);
        
        // 调用 AI 获取结果
        String endAnswer;
        try {
            endAnswer = aiManager.doChat(chatMessages);
        } catch (Exception e) {
            log.error("AI调用失败，面试ID: {}, 错误: {}", mockInterview.getId(), e.getMessage());
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "AI服务暂时不可用，请稍后重试");
        }
        
        if (StrUtil.isBlank(endAnswer)) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "AI回复为空，请重试");
        }
        
        ChatMessage endAssistantMessage = ChatMessage.builder().role(ChatMessageRole.ASSISTANT).content(endAnswer).build();
        chatMessages.add(endAssistantMessage);
        
        // 保存消息记录，并且更新状态
        List<MockInterviewChatMessage> mockInterviewChatMessages = transformFromChatMessage(chatMessages);
        String newJsonStr = JSONUtil.toJsonStr(mockInterviewChatMessages);
        
        MockInterview newUpdateMockInterview = new MockInterview();
        newUpdateMockInterview.setStatus(MockInterviewStatusEnum.ENDED.getValue());
        newUpdateMockInterview.setId(mockInterview.getId());
        newUpdateMockInterview.setMessages(newJsonStr);
        
        boolean newResult = this.updateById(newUpdateMockInterview);
        ThrowUtils.throwIf(!newResult, ErrorCode.SYSTEM_ERROR, "更新失败");
        
        log.info("面试结束成功，面试ID: {}", mockInterview.getId());
        return cleanAiResponse(endAnswer);
    }

    /**
     * 处理 AI 对话消息事件
     *
     * @param mockInterviewEventRequest
     * @param mockInterview
     * @return
     */
    private String handleChatMessageEvent(MockInterviewEventRequest mockInterviewEventRequest, MockInterview mockInterview) {
        String message = mockInterviewEventRequest.getMessage();
        if (StrUtil.isBlank(message)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "消息内容不能为空");
        }
        
        // 构造消息列表，注意需要先获取之前的消息记录
        String historyMessage = mockInterview.getMessages();
        List<MockInterviewChatMessage> historyMessageList = new ArrayList<>();
        
        // 安全地解析历史消息
        if (StrUtil.isNotBlank(historyMessage)) {
            try {
                historyMessageList = JSONUtil.parseArray(historyMessage).toList(MockInterviewChatMessage.class);
            } catch (Exception e) {
                // 如果解析失败，记录日志并使用空列表
                log.warn("解析历史消息失败，面试ID: {}, 错误: {}", mockInterview.getId(), e.getMessage());
                historyMessageList = new ArrayList<>();
            }
        }
        
        final List<ChatMessage> chatMessages = transformToChatMessage(historyMessageList);
        final ChatMessage chatUserMessage = ChatMessage.builder().role(ChatMessageRole.USER).content(message).build();
        chatMessages.add(chatUserMessage);
        
        // 调用 AI 获取结果
        String chatAnswer;
        try {
            chatAnswer = aiManager.doChat(chatMessages);
        } catch (Exception e) {
            log.error("AI调用失败，面试ID: {}, 错误: {}", mockInterview.getId(), e.getMessage());
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "AI服务暂时不可用，请稍后重试");
        }
        
        if (StrUtil.isBlank(chatAnswer)) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "AI回复为空，请重试");
        }
        
        ChatMessage chatAssistantMessage = ChatMessage.builder().role(ChatMessageRole.ASSISTANT).content(chatAnswer).build();
        chatMessages.add(chatAssistantMessage);
        
        // 保存消息记录，并且更新状态
        List<MockInterviewChatMessage> mockInterviewChatMessages = transformFromChatMessage(chatMessages);
        String newJsonStr = JSONUtil.toJsonStr(mockInterviewChatMessages);
        MockInterview newUpdateMockInterview = new MockInterview();
        newUpdateMockInterview.setId(mockInterview.getId());
        newUpdateMockInterview.setMessages(newJsonStr);
        
        // 如果 AI 主动结束了面试，更改状态
        if (chatAnswer.contains("【面试结束】")) {
            newUpdateMockInterview.setStatus(MockInterviewStatusEnum.ENDED.getValue());
        }
        
        boolean newResult = this.updateById(newUpdateMockInterview);
        ThrowUtils.throwIf(!newResult, ErrorCode.SYSTEM_ERROR, "更新失败");
        return cleanAiResponse(chatAnswer);
    }

    /**
     * 清理AI回答，移除不必要的格式化内容
     *
     * @param aiResponse AI原始回答
     * @return 清理后的回答
     */
    private String cleanAiResponse(String aiResponse) {
        if (StrUtil.isBlank(aiResponse)) {
            return aiResponse;
        }
        
        String cleaned = aiResponse;
        
        // 移除常见的AI回答前缀
        cleaned = cleaned.replaceAll("^(AI:|Assistant:|面试官:|系统:|System:|候选人:|用户:|User:)\\s*", "");
        
        // 移除可能的系统提示回显（通常以特定格式开头）
        cleaned = cleaned.replaceAll("^你是一位.*?请你.*?\\n", "");
        cleaned = cleaned.replaceAll("^作为.*?我将.*?\\n", "");
        cleaned = cleaned.replaceAll("^根据.*?要求.*?\\n", "");
        
        // 移除对话历史回显模式（如：用户：xxx 面试官：xxx）
        cleaned = cleaned.replaceAll("(用户|候选人|面试官|AI)：.*?\\n", "");
        cleaned = cleaned.replaceAll("(User|Candidate|Interviewer|AI):\\s*.*?\\n", "");
        
        // 移除可能的完整系统提示回显
        cleaned = cleaned.replaceAll("必须满足如下要求：.*?(?=\\n[^\\d]|$)", "");
        cleaned = cleaned.replaceAll("\\d+\\.\\s+.*?(?=\\n\\d+\\.|\\n[^\\d]|$)", "");
        
        // 移除markdown格式标记
        cleaned = cleaned.replaceAll("```[a-zA-Z]*\\n", "");
        cleaned = cleaned.replaceAll("```", "");
        
        // 移除多余的换行符
        cleaned = cleaned.replaceAll("\\n{3,}", "\\n\\n");
        
        // 移除开头和结尾的空白字符
        cleaned = cleaned.trim();
        
        // 如果清理后内容为空，返回原始内容
        if (StrUtil.isBlank(cleaned)) {
            return aiResponse.trim();
        }
        
        return cleaned;
    }

    /**
     * 处理 AI 对话开始事件
     *
     * @param mockInterview
     * @return
     */
    private String handleChatStartEvent(MockInterview mockInterview) {
        // 检查面试状态
        if (!Objects.equals(MockInterviewStatusEnum.TO_START.getValue(), mockInterview.getStatus())) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "面试已经开始或已结束，无法重复开始");
        }
        
        // 构造消息列表
        // 定义 AI 的 Prompt
        String systemPrompt = String.format("你是一位专业的程序员面试官，我是候选人，来应聘 %s 的 %s 岗位，面试难度为 %s。请你向我依次提出问题（建议10-15个问题），我也会依次回复。在这期间请完全保持真人面试官的口吻，比如适当引导学员、或者表达出你对学员回答的态度。\n" +
                "必须满足如下要求：\n" +
                "1. 当学员回复 \"开始\" 时，你要正式开始面试，先简单介绍一下面试流程，然后提出第一个问题\n" +
                "2. 每次只问一个问题，等待学员回答后再提出下一个问题\n" +
                "3. 当学员表示希望 \"结束面试\" 时，你要结束面试\n" +
                "4. 此外，当你觉得这场面试可以结束时（比如候选人回答结果较差、不满足工作年限的招聘需求、或者候选人态度不礼貌），必须主动提出面试结束，不用继续询问更多问题了。并且要在回复中包含字符串【面试结束】\n" +
                "5. 面试结束后，应该给出候选人整场面试的表现和总结。\n" +
                "6. 请保持回答简洁明了，避免过长的回复。\n" +
                "7. 重要：只返回你当前的回答内容，不要重复之前的对话历史，不要回显系统提示。", 
                mockInterview.getWorkExperience(), mockInterview.getJobPosition(), mockInterview.getDifficulty());
        
        String userPrompt = "开始";
        final List<ChatMessage> messages = new ArrayList<>();
        final ChatMessage systemMessage = ChatMessage.builder().role(ChatMessageRole.SYSTEM).content(systemPrompt).build();
        final ChatMessage userMessage = ChatMessage.builder().role(ChatMessageRole.USER).content(userPrompt).build();
        messages.add(systemMessage);
        messages.add(userMessage);
        
        // 调用 AI 获取结果
        String answer;
        try {
            answer = aiManager.doChat(messages);
        } catch (Exception e) {
            log.error("AI调用失败，面试ID: {}, 错误: {}", mockInterview.getId(), e.getMessage());
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "AI服务暂时不可用，请稍后重试");
        }
        
        if (StrUtil.isBlank(answer)) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "AI回复为空，请重试");
        }
        
        ChatMessage assistantMessage = ChatMessage.builder().role(ChatMessageRole.ASSISTANT).content(answer).build();
        messages.add(assistantMessage);
        
        // 保存消息记录，并且更新状态
        List<MockInterviewChatMessage> chatMessageList = transformFromChatMessage(messages);
        String jsonStr = JSONUtil.toJsonStr(chatMessageList);
        
        // 操作数据库进行更新
        MockInterview updateMockInterview = new MockInterview();
        updateMockInterview.setStatus(MockInterviewStatusEnum.IN_PROGRESS.getValue());
        updateMockInterview.setId(mockInterview.getId());
        updateMockInterview.setMessages(jsonStr);
        
        boolean result = this.updateById(updateMockInterview);
        ThrowUtils.throwIf(!result, ErrorCode.SYSTEM_ERROR, "更新失败");
        
        log.info("面试开始成功，面试ID: {}", mockInterview.getId());
        return cleanAiResponse(answer);
    }

    /**
     * 消息记录对象转换
     *
     * @param chatMessageList
     * @return
     */
    List<MockInterviewChatMessage> transformFromChatMessage(List<ChatMessage> chatMessageList) {
        return chatMessageList.stream().map(chatMessage -> {
            MockInterviewChatMessage mockInterviewChatMessage = new MockInterviewChatMessage();
            mockInterviewChatMessage.setRole(chatMessage.getRole().value());
            mockInterviewChatMessage.setMessage(chatMessage.getContent().toString());
            return mockInterviewChatMessage;
        }).collect(Collectors.toList());
    }

    /**
     * 消息记录对象转换
     *
     * @param chatMessageList
     * @return
     */
    List<ChatMessage> transformToChatMessage(List<MockInterviewChatMessage> chatMessageList) {
        if (chatMessageList == null || chatMessageList.isEmpty()) {
            return new ArrayList<>();
        }
        
        return chatMessageList.stream()
                .filter(chatMessage -> chatMessage != null && StrUtil.isNotBlank(chatMessage.getRole()) && StrUtil.isNotBlank(chatMessage.getMessage()))
                .map(chatMessage -> {
                    try {
                        ChatMessageRole role = ChatMessageRole.valueOf(StringUtils.upperCase(chatMessage.getRole()));
                        return ChatMessage.builder()
                                .role(role)
                                .content(chatMessage.getMessage())
                                .build();
                    } catch (IllegalArgumentException e) {
                        log.warn("无效的消息角色: {}, 跳过该消息", chatMessage.getRole());
                        return null;
                    }
                })
                .filter(chatMessage -> chatMessage != null)
                .collect(Collectors.toList());
    }
}